package br.com.gerenciamento.pg.framework.jpa.eclipselink.repository;

import java.security.AccessController;
import java.security.PrivilegedActionException;

import org.eclipse.persistence.exceptions.QueryException;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;

/**
 * 
 * @author wolmirgarbin
 *
 */
public class QueryByExamplePolicy extends org.eclipse.persistence.queries.QueryByExamplePolicy {

	private static final long serialVersionUID = 1633907792503179786L;

	@Override @SuppressWarnings({ "rawtypes", "unchecked" })
	public Expression completeExpression(Expression expression, Object attributeValue, Class attributeValueClass) {
		if(this.valuesToExclude.keySet().contains(expression.getName().toLowerCase()))
			return null;
		
        String operation = this.getOperation(attributeValue.getClass());

        if (operation == null) {
            return expression.equal(attributeValue);
        }

        if(operation.startsWith("likeIgnoreCase")){
        	if("likeIgnoreCaseStart".equals(operation)){
        		attributeValue = attributeValue.toString()+"%";
        	}else if("likeIgnoreCaseEnd".equals(operation)){
        		attributeValue = "%"+attributeValue.toString();
        	}else if("likeIgnoreCaseMiddle".equals(operation)){
        		attributeValue = "%"+attributeValue.toString()+"%";
        	}
        	operation = "likeIgnoreCase";
        }
        
        Class[] argTypes = { attributeValueClass };
        Object[] args = { attributeValue };
        try {
            java.lang.reflect.Method anOperator = Helper.getDeclaredMethod(ClassConstants.Expression_Class, operation, argTypes);
            if (anOperator == null) {
                throw QueryException.methodDoesNotExistOnExpression(operation, argTypes);
            }
            if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
                try{
                    expression = (Expression)AccessController.doPrivileged(new PrivilegedMethodInvoker(anOperator, expression, args));
                }catch (PrivilegedActionException ex){
                    throw (RuntimeException) ex.getCause();
                }
            }else{
                expression = (Expression)PrivilegedAccessHelper.invokeMethod(anOperator, expression, args);
            }
        } catch (NoSuchMethodException nsme) {
            Class superClass = attributeValueClass.getSuperclass();
            if (superClass != null) {
                return completeExpression(expression, attributeValue, superClass);
            } else {
                throw QueryException.methodDoesNotExistOnExpression(operation, argTypes);
            }
        } catch (IllegalAccessException iae) {
            throw QueryException.methodDoesNotExistOnExpression(operation, argTypes);
        } catch (java.lang.reflect.InvocationTargetException ite) {
            throw QueryException.methodDoesNotExistOnExpression(operation, argTypes);
        }
        return expression;
    }

	public void excludeValue(String value) {
		super.excludeValue(value.toLowerCase());
	}
	
}
